Skip to content

UI evaluators: isolated, model-pinned evaluator runs and start_evaluation - #261

Merged
MHohlios merged 4 commits into
mainfrom
wiffletree/ui-evaluators-isolated-model-pinned-evaluator-ru
Nov 4, 2026
Merged

MHohlios merged 4 commits into
mainfrom
wiffletree/ui-evaluators-isolated-model-pinned-evaluator-ru

Conversation

@MHohlios

@MHohlios MHohlios commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Summary

This is the foundation of UI evaluators, the first of four stacked PRs for the OpenSpec change ui-evaluators, whose approved mockup is in openspec/changes/ui-evaluators/ui/mockups.html. A coordinator can now start a blind evaluator run on one exact model, with only a prompt and a run folder. It is woken with one short line when the run ends. The app driver and the desktop driver come in the stacked PRs that follow.

  • Evaluator runs. This adds a new launch kind and an evaluations table. A run belongs to a project, never to a ticket or worktree. Every run starts a fresh session, which is archived when it ends.
  • Provider-enforced isolation. A run has no shell, web access, coordination tools, brain or repository. It reads and writes only its run folder, and its first message is exactly prompt.md.
    • Claude runs with -p, --setting-sources "", a strict empty MCP config, dontAsk, Read,Glob,Grep,Write,Edit limited to the folder, and auto memory off.
    • Codex runs exec --ignore-user-config --ignore-rules with a workspace-write sandbox at the folder, no network and no web search. It gets its own CODEX_HOME, which holds only a link to auth.json, and an empty HOME, so neither ~/.codex/AGENTS.md nor the user's skills reach it.
    • The environment is cleared to an allowlist, so no WORKSPACE_* variable passes through.
  • Exact model. A run accepts only the models the provider's CLI lists, including full IDs, and never uses Who runs what or a fallback. It records the model the provider reports. A full ID that drifts fails the run. At a usage limit the run waits for the reset in the same session.
  • Tools. Coordinators get start_evaluation, list_evaluations and stop_evaluation. Refusals name the reason. The end message is only Run <id> <state> · model <m> · folder <f> · <N min>.
  • Authorization. Each project can be set to off, app or desktop, and it is off by default. Only the human sets it, through the Inbox card raised on a project's first run. Closing the project turns it off.
  • Queue and screen lock. App runs run side by side. Desktop runs go first in, first out with one screen holder; desktop mode is refused until the desktop-driver PR lands.
  • Recovery. A run cut short by a host crash or kill fails at the next start, and its coordinator is woken.

Decisions

  • Codex rewrites auth.json in place on a token refresh, so linking it from the evaluator's Codex home is safe. This was checked with a probe using fake tokens and a local refresh endpoint; details are in design.md.
  • The end message includes the model the provider reported, so model drift is visible. That model is provider metadata, not report text.

How it was tested

  • cargo fmt --check and cargo clippy --workspace --all-targets -D warnings are clean.
  • cargo test --workspace: 2557 tests pass.
  • New tests cover:
    • the Claude and Codex launch arguments and environment;
    • the start and tool-call checks;
    • the refusals;
    • model pinning and drift;
    • waiting at a limit without a fallback;
    • the end message;
    • the queue and screen lock;
    • stop, close and startup recovery;
    • contract tests for the three tools.
  • The ignored live tests in tests/evaluator_isolation.rs ran against the real Claude and Codex CLIs. Neither saw the user's CLAUDE.md, AGENTS.md or skills, and neither could write outside its folder.

Follow-ups

  • The evaluator environment allowlist drops the provider's own auth, config and proxy variables (ANTHROPIC_API_KEY, CLAUDE_CONFIG_DIR, HTTPS_PROXY), so a run could fail to start where they are needed (crates/workspace-host/src/provider/evaluator.rs:20).

Reviewed with Wiffletree: 1 full review and 0 re-checks, 2 rounds (Tests, Claude, Codex, Style)

🤖 Generated with Claude Code

mhohlios added 4 commits November 4, 2026 06:30
A coordinator starts a blind evaluator with start_evaluation(run_folder,
provider, model, effort, mode). Each run is a fresh session of the new
evaluator role, outside every agent tree, whose only message is the run
folder's prompt.md. Claude runs with no setting sources, an empty strict
MCP config, dontAsk and file tools scoped to the folder; Codex runs
sandboxed in the folder with no shell, web or MCP, from a Codex home that
holds only a link to the human's auth.json, because --ignore-user-config
still loads ~/.codex/AGENTS.md. The environment is cleared to a short
allowlist, so no WORKSPACE_* variable reaches the run.

The model is checked against detection and the provider's listed models
and pinned; at a usage limit the run waits for the reset and never falls
back. The human allows evaluators per project through an Inbox card or
set_evaluator_permission; closing the project turns them off. Desktop runs
are refused until the desktop driver, but share one queue and screen lock.
When a run ends its coordinator gets only its id, state, folder and
duration. list_evaluations and stop_evaluation complete the tools, and the
human can stop any run.
A model is now checked only against its CLI's own list, full IDs such as
claude-opus-5-5 and aliases alike. When the list has not been read yet,
start_evaluation refuses with that reason and the service reads it, so a
repeated call succeeds.

Each run records the model its provider names: Claude's from its start
record, Codex's from the turn_context of its session record in the
evaluator's Codex home, since its JSON stream names none. A run started on
a full ID whose provider names another model fails at once, with the
reason for the human. list_evaluations and the end message show the
reported model.

The design records that Codex 0.160.0 rewrites auth.json in place on a
token refresh: a probe with a throwaway home, a fake stale token behind a
link and a local token endpoint kept the link and the target's inode, so
the evaluator home's link to the human's auth.json stays safe.
… from Codex

A run whose turn a crash, kill or long quit cut short now fails when the
host next starts, "Wiffletree stopped during the run.", and its
coordinator gets the end message, as job runs are ended. A run whose
prompt is still queued, or that waits for its limit's reset, goes on.

A separate CODEX_HOME still let Codex find the human's skills under
~/.agents/skills: a request captured by a local endpoint carried them,
and neither skip_host_skill_discovery nor turning off skill_search
removed them. The evaluator's Codex now runs with an empty HOME beside its
Codex home; only Codex's bundled system skills remain. The live isolation
tests now also check that none of the human's skill names reach a run.

The desktop skills view expects the coordinator core's v16.
@MHohlios
MHohlios merged commit 2660807 into main Nov 4, 2026
9 checks passed
@MHohlios
MHohlios deleted the wiffletree/ui-evaluators-isolated-model-pinned-evaluator-ru branch November 4, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant